/**
 * @file bsp_gnss.c
 * @brief 
 * @author  ()
 * @version 1.0
 * @date 2024-09-13
 * 
 * @copyright Copyright (C) 2019 Queclink Wireless Solutions (ShenZhen) Co., Ltd. All Rights Reserved.
 * 
 * @par 修改日志:
 * <table>
 * <tr><th>Date       <th>Version <th>Author  <th>Description
 * <tr><td>2024-09-13 <td>1.0     <td>     <td>内容
 * </table>
 */
#include "bsp_gnss.h"
#include "bsp_uart.h"
#include "hal_adapter.h"
#include "qlcommon.h"
#include "FreeRTOS.h"
#include "task.h"

#include "global.h"

#include "FreeRTOS.h"
#include "lettershell/shell.h"

extern UART_HandleTypeDef gnss_uart_ctx;
serial_t gnss_serial = {0};

#define GNSS_FIRMWARE_DOWNLOAD  (0)

static bool nmea_transparent_en = false; /* nmea数据透传使能标志 */

/**
 * @brief GNSS串口读取
 * @param  serial           My Param doc
 * @param  data             My Param doc
 * @return int32_t 
 */
int32_t serial_rx_read(serial_t *serial, uint8_t *data)
{
    ssize_t wr_cnt = 0;

    wr_cnt = bsp_uart_read(gnss_uart_id, (void*)data, 1);

    return wr_cnt > 0 ? 0 : -1;
}

/* nmea 信息透传控制,仅shell的log指令使用 */
static void nmea_transparent_switch(bool en)
{
    taskENTER_CRITICAL();
    nmea_transparent_en = en;
    taskEXIT_CRITICAL();
}

int32_t shell_nmea_print(int32_t argc, char *argv[])
{
    if (2 == argc && 1 == strlen(argv[1])) {
        nmea_transparent_switch(atoi(argv[1]));
    }
    return 0;
}

SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN) | SHELL_CMD_DISABLE_RETURN,
                 nmea, 
                 shell_nmea_print, 
                 control nmea log printf(0:disable, 1:enable));

SHELL_EXPORT_VAR(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_VAR_CHAR), \
                    gnss_data, &nmea_transparent_en, var for gnss raw data print);

/**
 * @brief gnss uart gpio init
 */
void bsp_gnss_gpio_init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    /* 1. Initializes the peripherals clock */
    gnss_gpioclk_enable();

    /* 2. configure the gnss power pin */
    GPIO_InitStruct.Pin = GNSS_PWR_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(GNSS_PWR_PORT, &GPIO_InitStruct);

    /* 3. configure the gnss wakeup pin */
    GPIO_InitStruct.Pin = GNSS_WAKEUP_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(GNSS_WAKEUP_PORT, &GPIO_InitStruct);
    HAL_GPIO_WritePin(GNSS_WAKEUP_PORT, GNSS_WAKEUP_PIN, GPIO_PIN_RESET);

    /* 4. configure the gnss tx/rx pin  */
    GPIO_InitStruct.Pin = GNSS_UART_TX_PIN | GNSS_UART_RX_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    GPIO_InitStruct.Alternate = GNSS_UART_PORT_AF;
    HAL_GPIO_Init(GNSS_UART_PORT, &GPIO_InitStruct);
}

/**
 * @brief gnss数据写入
 * @param  data             My Param doc
 * @param  cnt              My Param doc
 * @return ssize_t 
 */
ssize_t bsp_gnss_write(const void *data, size_t cnt)
{
    return bsp_uart_itwrite(gnss_uart_id, data, cnt);
}

/**
 * @brief gnss数据读取
 * @param  data             My Param doc
 * @param  max_size         My Param doc
 * @return ssize_t 
 */
ssize_t bsp_gnss_read(void *data, size_t max_size)
{
    ssize_t real_len = 0;

    while (real_len < max_size) {
        if (0 != serial_rx_read(&gnss_serial, (uint8_t *)data + real_len))
            break;

        real_len++;
    };

    /* 透传数据 */
    if (nmea_transparent_en && real_len > 0) {
        for (int32_t i = 0; i < real_len; i++)
            printf("%c", ((char *)data)[i]);
    }

    return real_len;
}

/**
 * @brief 设置波特率
 * @param  bps          GNSS串口波特率 115200/921600 可选
 */
void bsp_gnss_set_baudrate(uint32_t bps)
{
    if (115200 != bps && 921600 != bps)
        return;

    bsp_uart_set_baudrate(gnss_uart_id, bps);
}

/**
 * @brief gnss电源开
 */
void bsp_gnss_power_on(void)
{
    HAL_GPIO_WritePin(GNSS_PWR_PORT, GNSS_PWR_PIN, GPIO_PIN_SET);
}

/**
 * @brief gnss电源关
 */
void bsp_gnss_power_off(void)
{
    HAL_GPIO_WritePin(GNSS_PWR_PORT, GNSS_PWR_PIN, GPIO_PIN_RESET);
}

void gnss_hw_init(void)
{
#if GNSS_FIRMWARE_DOWNLOAD /* 用于烧录固件时的初始化 */
    GPIO_InitTypeDef GPIO_InitStruct = {0};

    /* GPIO Ports Clock Enable */
    gnss_gpioclk_enable();

    GPIO_InitStruct.Pin = GNSS_PWR_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(GNSS_PWR_PORT, &GPIO_InitStruct);
    
    bsp_gnss_power_off();
    bsp_gnss_power_on();
#else
    /* 1. gnss gpio init */
    bsp_gnss_gpio_init();

    /* 2. gnss poweroff */
    bsp_gnss_power_off();

    /* 3. Peripheral clock enable */
    gnss_uartclk_enable();

    /* 4. init the usart port */
    bsp_uart_init(gnss_uart_id);
#endif
}

/**
 * @brief 进入休眠
 * 
 * @return int32_t 
 */
void gnss_uart_sleep(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};

    HAL_GPIO_DeInit(GNSS_UART_PORT, GNSS_UART_TX_PIN|GNSS_UART_RX_PIN);
    HAL_GPIO_DeInit(GNSS_WAKEUP_PORT, GNSS_WAKEUP_PIN);
    HAL_GPIO_DeInit(GNSS_PWR_PORT, GNSS_PWR_PIN);

    GPIO_InitStruct.Pin = GNSS_UART_TX_PIN|GNSS_UART_RX_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    GPIO_InitStruct.Alternate = GNSS_UART_PORT_AF;
    HAL_GPIO_Init(GNSS_UART_PORT, &GPIO_InitStruct);

    /* PWR pin */
    GPIO_InitStruct.Pin = GNSS_PWR_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(GNSS_PWR_PORT, &GPIO_InitStruct);

    /* Wakeup pin */
    GPIO_InitStruct.Pin = GNSS_WAKEUP_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(GNSS_WAKEUP_PORT, &GPIO_InitStruct);
}

/**
 * @brief 使能串口唤醒
 * 
 */
void gnss_uart_wakeup(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};

    HAL_GPIO_DeInit(GNSS_UART_PORT, GNSS_UART_TX_PIN|GNSS_UART_RX_PIN);
    HAL_GPIO_DeInit(GNSS_WAKEUP_PORT, GNSS_WAKEUP_PIN);
    HAL_GPIO_DeInit(GNSS_PWR_PORT, GNSS_PWR_PIN);

    GPIO_InitStruct.Pin = GNSS_UART_TX_PIN|GNSS_UART_RX_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    GPIO_InitStruct.Alternate = GNSS_UART_PORT_AF;
    HAL_GPIO_Init(GNSS_UART_PORT, &GPIO_InitStruct);

    /* PWR pin */
    GPIO_InitStruct.Pin = GNSS_PWR_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(GNSS_PWR_PORT, &GPIO_InitStruct);

    /* Wakeup pin */
    GPIO_InitStruct.Pin = GNSS_WAKEUP_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(GNSS_WAKEUP_PORT, &GPIO_InitStruct);
}
